﻿/**************************************************************
 *
 * 唯一标识：1ffcac2b-4d2f-41cc-8707-1c4baeb8653c
 * 命名空间：Sgr.Security
 * 创建时间：2023/8/28 11:46:24
 * 机器名称：DESKTOP-S0D075D
 * 创建者：antho
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：
 *
 **************************************************************/

using Sgr.Caching.Services;
using Sgr.UPMS;
using Sgr.UPMS.Application.Queries;
using Sgr.UPMS.Application.ViewModels;
using System.Security.Claims;

namespace Sgr.Security
{
    /// <summary>
    /// UPMS系统功能权限授权服务
    /// 负责用户功能权限的验证和授权管理
    /// </summary>
    public class UpmsFunctionPermissionGrantingService : IFunctionPermissionGrantingService
    {
        #region 私有字段

        private readonly IServiceScopeFactory _serviceScopeFactory;
        private readonly ICacheManager _cacheManager;

        #endregion 私有字段

        /// <summary>
        /// 初始化功能权限授权服务
        /// </summary>
        /// <param name="serviceScopeFactory">服务作用域工厂</param>
        /// <param name="cacheManager">缓存管理器</param>
        public UpmsFunctionPermissionGrantingService(
            IServiceScopeFactory serviceScopeFactory,
            ICacheManager cacheManager)
        {
            _serviceScopeFactory = serviceScopeFactory;
            _cacheManager = cacheManager;
        }

        public virtual async Task<bool> IsGrantedAsync(string orgId, string userId, string functionPermissionName)
        {
            if (string.IsNullOrEmpty(functionPermissionName))
                return false;

            if (!long.TryParse(orgId, out long longOrgId))
                return false;

            if (!long.TryParse(userId, out long longUserId))
                return false;

            // 优先从缓存中获取用户权限信息
            (bool success, OutUserPermissionViewModel? permission) = await _cacheManager.TryGetValueAsync<OutUserPermissionViewModel>(
                CacheKeys.GetUserPermissionKey(longOrgId, longUserId));

            if (!success)
            {
                // 如果缓存中没有，则从数据库中加载用户权限信息
                // 由于 UpmsFunctionPermissionGrantingService 被注册为单例，所以需要创建一个新的作用域来获取服务
                using var scope = _serviceScopeFactory.CreateScope();
                var userPermissionQueries = scope.ServiceProvider.GetRequiredService<IUserPermissionQueries>();
                permission = await userPermissionQueries.GetUserPermissionAsync(longUserId, longOrgId);
            }

            // 无法查询到，则返回false
            if (permission == null)
                return false;

            return permission.Permissions.Contains(functionPermissionName);
        }

        public Task<bool> IsGrantedAsync(string orgId, string userId, FunctionPermissionRequirement requirement)
        {
            return IsGrantedAsync(orgId, userId, requirement.Permission.Name);
        }

        public Task<bool> IsGrantedAsync(ICurrentUser currentUser, FunctionPermissionRequirement requirement)
        {
            if (string.IsNullOrEmpty(currentUser.OrgId))
                throw new Sgr.Exceptions.BusinessException("无法获取用户所属组织信息，请重新登录");

            if (string.IsNullOrEmpty(currentUser.Id))
                throw new Sgr.Exceptions.BusinessException("无法获取用户身份信息，请重新登录");

            return IsGrantedAsync(currentUser.OrgId!, currentUser.Id!, requirement);
        }

        public async Task<bool> IsGrantedAsync(ClaimsPrincipal claimsPrincipal, FunctionPermissionRequirement requirement)
        {
            var claimUserId = claimsPrincipal.Claims.FirstOrDefault(f => f.Type == Constant.CLAIM_USER_ID);
            if (claimUserId == null)
                return false;

            var claimOrgId = claimsPrincipal.Claims.FirstOrDefault(f => f.Type == Constant.CLAIM_USER_ORGID);
            if (claimOrgId == null)
                return false;

            return await IsGrantedAsync(claimOrgId.Value, claimUserId.Value, requirement);
        }

        public async Task<bool> IsGrantedAsync(ClaimsPrincipal claimsPrincipal, string functionPermissionName)
        {
            var claimUserId = claimsPrincipal.Claims.FirstOrDefault(f => f.Type == Constant.CLAIM_USER_ID);
            if (claimUserId == null)
                return false;

            var claimOrgId = claimsPrincipal.Claims.FirstOrDefault(f => f.Type == Constant.CLAIM_USER_ORGID);
            if (claimOrgId == null)
                return false;

            return await IsGrantedAsync(claimOrgId.Value, claimUserId.Value, functionPermissionName);
        }
    }
}